/**
  ******************************************************************************
  * @file    sym32l010_hal_spi.c
  * @author  AE Team
  * @version 1.0.3
  * @date    2024-05-28
  * @brief   SPI HAL module driver.
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 SIYIMicro.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */


/******************************************************************************/
/* Include files                                                              */
/******************************************************************************/
#include "sym32l010_hal_spi.h"
#include "sym32l010_hal_systick.h"


/*******************************************************************************
  * @brief  SPI 初始化
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示初始化成功
  *                      HAL_ERROR 表示初始化失败
  * @note   需通过APBENx寄存器使能SPIx的时钟后，才可调用该函数
  *         需要在SPI禁止的时候才可调用该函数
  */
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hSpi)
{
    if (hSpi == NULL)
    {
        return HAL_ERROR;
    }

    hSpi->Instance->CR1 = (uint32_t)hSpi->Init.MasterSmpCfg |
                          (uint32_t)hSpi->Init.SlaveMisoCfg |
                          (uint32_t)hSpi->Init.FilterEn     |
                          (uint32_t)hSpi->Init.CommLines    |
                          (uint32_t)hSpi->Init.MasterGap    |
                          (uint32_t)hSpi->Init.DataWidth    |
                          (uint32_t)hSpi->Init.FirstBit     |
                          (uint32_t)hSpi->Init.SckSource    |
                          (uint32_t)hSpi->Init.SckPolarity  |
                          (uint32_t)hSpi->Init.SckPhase     |
                          (uint32_t)hSpi->Init.NcsMode      |
                          (uint32_t)hSpi->Init.WorkMode     |
                          (uint32_t)((hSpi->Init.SckSource > SPI_SCKSRC_PCLKDIV8) ?
                                     hSpi->Init.FilterEn : SPI_FILTER_DISABLE);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  SPI 模块反初始化
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示反初始化成功
  *                      HAL_ERROR 表示反初始化失败
  */
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hSpi)
{
    if (hSpi == NULL)
    {
        return HAL_ERROR;
    }

    REGBITS_CLR(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_SPI1_Msk);
    REGBITS_SET(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_SPI1_Msk);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  SPI 使能
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示使能成功
  *                      HAL_ERROR 表示使能失败
  */
HAL_StatusTypeDef HAL_SPI_Enable(SPI_HandleTypeDef *hSpi)
{
    if (hSpi == NULL)
    {
        return HAL_ERROR;
    }

    REGBITS_SET(hSpi->Instance->CR2, SPIx_CR2_EN_Msk);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  SPI 禁止
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示禁能成功
  *                      HAL_ERROR 表示禁能失败
  */
HAL_StatusTypeDef HAL_SPI_Disable(SPI_HandleTypeDef *hSpi)
{
    if (hSpi == NULL)
    {
        return HAL_ERROR;
    }

    REGBITS_CLR(hSpi->Instance->CR2, SPIx_CR2_EN_Msk);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  通过查询方式发送SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pData      : 待发送的数据的指针
  * @param  Size       : 待发送的数据的帧数
  * @param  TimeOut    : 发送数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      表示成功完成发送
  *                      HAL_TIMEOUT 表示接收超时
  *                      HAL_ERROR   表示接收出错
  * @note   1. 需要使能SYSTICK
  *         2. 可用于双线全双工模式发送、单线半双工模式发送、单工模式只发
  */
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hSpi, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    if ((hSpi == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    hSpi->pTxBuffPtr  = (uint8_t *)pData;
    hSpi->TxXferSize  = Size;
    hSpi->TxXferCount = Size;
    hSpi->pRxBuffPtr  = NULL;
    hSpi->RxXferSize  = 0;
    hSpi->RxXferCount = 0;

    if (hSpi->Init.CommLines == SPI_COMM1LINE_HalfDuplex)             // 单线半双工模式切换总线为输出模式
    {
        HAL_SPI_1LINE_HALFDUPLEX_TXMODE(hSpi);
    }

    uint32_t TickStart = HAL_GetTick();
    uint32_t tmp32;

    hSpi->Instance->ICR = 0;
    if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
    {
        while (hSpi->TxXferCount > 0)
        {
            tmp32 = hSpi->Instance->ISR;
            if (tmp32 & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_UD))
            {
                return HAL_ERROR;
            }
            if (tmp32 & SPI_IT_FLAG_TXE)
            {
                hSpi->Instance->DR = *((uint16_t *)hSpi->pTxBuffPtr);
                hSpi->pTxBuffPtr += 2;
                hSpi->TxXferCount--;
            }
            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }
    else
    {
        while (hSpi->TxXferCount > 0)
        {
            tmp32 = hSpi->Instance->ISR;
            if (tmp32 & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_UD))
            {
                return HAL_ERROR;
            }
            if (tmp32 & SPI_IT_FLAG_TXE)
            {
                hSpi->Instance->DR = *hSpi->pTxBuffPtr;
                hSpi->pTxBuffPtr++;
                hSpi->TxXferCount--;
            }
            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }

    if (hSpi->Instance->CR1 & SPIx_CR1_MSTR_Msk)                      // 主机模式，等待总线将BUF中的数据发送完成
    {
        while (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_BUSY))
        {
            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }

    return HAL_OK;
}


/*******************************************************************************
  * @brief  通过查询方式接收SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pData      : 待接收的数据的存放指针
  * @param  Size       : 待接收的数据的帧数
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      表示成功完成接收
  *                      HAL_TIMEOUT 表示接收超时
  *                      HAL_ERROR   表示接收出错
  * @note   1. 需要使能SYSTICK
  *         2. 可用于双线全双工模式接收、单线半双工模式接收、单工模式只收
  */
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hSpi, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    if ((hSpi == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    hSpi->pTxBuffPtr  = NULL;
    hSpi->TxXferSize  = 0;
    hSpi->TxXferCount = 0;
    hSpi->pRxBuffPtr  = (uint8_t *)pData;
    hSpi->RxXferSize  = Size;
    hSpi->RxXferCount = Size;

    if (hSpi->Init.CommLines == SPI_COMM1LINE_HalfDuplex)             // 单线半双工模式切换总线为输入模式
    {
        HAL_SPI_1LINE_HALFDUPLEX_RXMODE(hSpi);
    }

    uint32_t TickStart = HAL_GetTick();
    uint32_t tmp32;

    hSpi->Instance->ICR = 0;
    if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
    {
        while (hSpi->RxXferCount > 0)
        {
            hSpi->Instance->DR = 0x00;
            do
            {
                tmp32 = hSpi->Instance->ISR;
            }
            while ((tmp32 & SPI_IT_FLAG_RXNE) == 0);

            if (tmp32 & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_OV))
            {
                return HAL_ERROR;
            }

            *((uint16_t *)hSpi->pRxBuffPtr) = hSpi->Instance->DR;
            hSpi->pRxBuffPtr += 2;
            hSpi->RxXferCount--;

            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }
    else
    {
        while (hSpi->RxXferCount > 0)
        {
            hSpi->Instance->DR = 0x00;
            do
            {
                tmp32 = hSpi->Instance->ISR;
            }
            while ((tmp32 & SPI_IT_FLAG_RXNE) == 0);

            if (tmp32 & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_OV))
            {
                return HAL_ERROR;
            }

            *hSpi->pRxBuffPtr = hSpi->Instance->DR;
            hSpi->pRxBuffPtr++;
            hSpi->RxXferCount--;

            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }

    return HAL_OK;
}


/*******************************************************************************
  * @brief  通过查询方式发送并接收SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pTxData    : 待发送的数据的指针
  * @param  pRxData    : 待接收的数据的指针
  * @param  Size       : 待发送与接收的数据的帧数
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      表示成功完成发送与接收
  *                      HAL_TIMEOUT 表示操作超时
  *                      HAL_ERROR   表示操作出错
  * @note   1. 需要使能SYSTICK
  *         2. 仅用于双线全双工模式发送、双线全双工模式接收
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hSpi, uint8_t *pTxData,
                                                                   uint8_t *pRxData,
                                                                   uint32_t Size,
                                                                   uint32_t TimeOut)
{
    uint32_t txAllowed = 1U;                                          // 发送允许

    if ((hSpi == NULL) || (pTxData == NULL) || (pRxData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }
    if (hSpi->Init.CommLines != SPI_COMM2LINES_FullDuplex)
    {
        return HAL_ERROR;
    }

    hSpi->pTxBuffPtr  = (uint8_t *)pTxData;
    hSpi->TxXferSize  = Size;
    hSpi->TxXferCount = Size;
    hSpi->pRxBuffPtr  = (uint8_t *)pRxData;
    hSpi->RxXferSize  = Size;
    hSpi->RxXferCount = Size;

    uint32_t TickStart = HAL_GetTick();

    hSpi->Instance->ICR = 0;
    if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
    {
        if ((hSpi->Init.WorkMode == SPI_WORKMODE_SLAVE) || (hSpi->TxXferSize == 1U))
        {
            hSpi->Instance->DR = *((uint16_t *)hSpi->pTxBuffPtr);
            hSpi->pTxBuffPtr += 2;
            hSpi->TxXferCount--;
        }

        while ((hSpi->TxXferCount > 0U) || (hSpi->RxXferCount > 0U))
        {
            if ((txAllowed == 1U) && HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_TXE) && (hSpi->TxXferCount > 0U))
            {
                hSpi->Instance->DR = *((uint16_t *)hSpi->pTxBuffPtr);
                hSpi->pTxBuffPtr += 2;
                hSpi->TxXferCount--;
                txAllowed = 0U;                                       // 禁止发送数据，直到收到数据
            }

            if ((HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_RXNE)) && (hSpi->RxXferCount > 0U))
            {
                *((uint16_t *)hSpi->pRxBuffPtr) = (uint16_t)hSpi->Instance->DR;
                hSpi->pRxBuffPtr += 2;
                hSpi->RxXferCount--;
                txAllowed = 1U;                                       // 接收到数据，允许下次发送
            }

            if (hSpi->Instance->ISR & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_OV))
            {
                return HAL_ERROR;
            }
            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }
    else
    {
        if ((hSpi->Init.WorkMode == SPI_WORKMODE_SLAVE) || (hSpi->TxXferSize == 1U))
        {
            hSpi->Instance->DR = *hSpi->pTxBuffPtr;
            hSpi->pTxBuffPtr++;
            hSpi->TxXferCount--;
        }
        while ((hSpi->TxXferCount > 0U) || (hSpi->RxXferCount > 0U))
        {
            if ((txAllowed == 1U) && HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_TXE) && (hSpi->TxXferCount > 0U))
            {
                hSpi->Instance->DR = *hSpi->pTxBuffPtr;
                hSpi->pTxBuffPtr++;
                hSpi->TxXferCount--;
                txAllowed = 0U;                                       // 禁止发送数据，直到收到数据
            }

            if ((HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_RXNE)) && (hSpi->RxXferCount > 0U))
            {
                *hSpi->pRxBuffPtr = hSpi->Instance->DR;
                hSpi->pRxBuffPtr++;
                hSpi->RxXferCount--;
                txAllowed = 1U;                                       // 接收到数据，允许下次发送
            }

            if (hSpi->Instance->ISR & (SPI_IT_FLAG_MODF | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_OV))
            {
                return HAL_ERROR;
            }
            if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
            {
                return HAL_TIMEOUT;
            }
        }
    }

    return HAL_OK;
}


/*******************************************************************************
  * @brief  SPI 接收完成回调函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  * @note   1.当需要重写本回调函数时，可以在用户文件中重写本函数，而不应该在此处修改本函数。
  *         2.当重写本函数时请勿删除本函数内原有的代码。
  */
__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hSpi)
{
    HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_RXNE);
    hSpi->XferState = HAL_OK;

    /* USER CODE BEGIN */

    /* USER CODE END */
}


/*******************************************************************************
  * @brief  SPI以8BIT接收的中断处理函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  * @note
  */
static void SPI_RxISR_8BIT(SPI_HandleTypeDef *hSpi)
{
    *hSpi->pRxBuffPtr = hSpi->Instance->DR;
    hSpi->pRxBuffPtr++;
    hSpi->RxXferCount--;

    if (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_OV | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_MODF))
    {
        hSpi->XferState = HAL_ERROR;
        HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_RXNE);
    }
    if (hSpi->RxXferCount == 0)                                       // 所有数据接收完成
    {
        HAL_SPI_RxCpltCallback(hSpi);                                 // 执行接收完成回调函数
    }
}


/*******************************************************************************
  * @brief  SPI以16BIT接收的中断处理函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  */
static void SPI_RxISR_16BIT(SPI_HandleTypeDef *hSpi)
{
    *((uint16_t *)hSpi->pRxBuffPtr) = hSpi->Instance->DR;
    hSpi->pRxBuffPtr += 2;
    hSpi->RxXferCount--;

    if (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_OV | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_MODF))
    {
        hSpi->XferState = HAL_ERROR;
        HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_RXNE);
    }
    if (hSpi->RxXferCount == 0)                                       // 所有数据接收完成
    {
        HAL_SPI_RxCpltCallback(hSpi);                                 // 执行接收完成回调函数
    }
}


/*******************************************************************************
  * @brief  SPI 发送完成回调函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  * @note   1.当需要重写本回调函数时，可以在用户文件中重写本函数，而不应该在此处修改本函数。
  *         2.当重写本函数时请勿删除本函数内原有的代码。
  */
__weak void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hSpi)
{
    HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_TXE);
    if (hSpi->RxXferCount == 0)
    {
        if ((hSpi->Init.WorkMode == SPI_WORKMODE_MASTER) && (hSpi->RxXferSize == 0))   // 主机模式并且只用于发送
        {
            while (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_BUSY) == SPI_IT_FLAG_BUSY) { ; } // 等待数据从总线发送完成    
        }

        hSpi->XferState = HAL_OK;
    }

    /* USER CODE BEGIN */

    /* USER CODE END */
}


/*******************************************************************************
  * @brief  SPI以8BIT发送的中断处理函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  */
static void SPI_TxISR_8BIT(SPI_HandleTypeDef *hSpi)
{
    if (hSpi->TxXferCount > 0)
    {
        hSpi->Instance->DR = *hSpi->pTxBuffPtr;
        hSpi->pTxBuffPtr++;
        hSpi->TxXferCount--;

        if (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_UD | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_MODF))
        {
            hSpi->XferState = HAL_ERROR;
            HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_TXE);
        }
    }
    else                                                              // 所有数据发送完成
    {
        HAL_SPI_TxCpltCallback(hSpi);                                 // 执行发送完成回调函数
    }
}


/*******************************************************************************
  * @brief  SPI以16BIT发送的中断处理函数
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  */
static void SPI_TxISR_16BIT(SPI_HandleTypeDef *hSpi)
{
    if (hSpi->TxXferCount > 0)
    {
        hSpi->Instance->DR = *((uint16_t *)hSpi->pTxBuffPtr);
        hSpi->pTxBuffPtr += 2;
        hSpi->TxXferCount--;

        if (HAL_SPI_GET_FLAG(hSpi, SPI_IT_FLAG_UD | SPI_IT_FLAG_SSERR | SPI_IT_FLAG_MODF))
        {
            hSpi->XferState = HAL_ERROR;
            HAL_SPI_DISABLE_IT(hSpi, SPI_IT_SOURCE_TXE);
        }
    }
    else                                                              // 所有数据发送完成
    {
        HAL_SPI_TxCpltCallback(hSpi);                                 // 执行发送完成回调函数
    }
}


/*******************************************************************************
  * @brief  通过中断方式发送SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pData      : 待发送的数据的指针
  * @param  Size       : 待发送的数据的帧数
  * @retval HAL status : HAL_OK    表示配置SPI中断方式发送成功
  *                      HAL_ERROR 表示配置SPI中断方式发送失败
  *                      HAL_BUSY  表示SPI正处于通信状态
  * @note   1. 需要在SPIx的中断服务程序中调用 HAL_SPI_IRQHandler 函数
  *         2. 在调用前，需使能NVIC
  *         3. 可用于双线全双工模式发送、单线半双工模式发送、单工模式只发
  */
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hSpi, uint8_t *pData, uint32_t Size)
{
    if ((hSpi == NULL) || (pData == NULL) || (Size == 0U))
    {
        return HAL_ERROR;
    }
    if (hSpi->XferState == HAL_BUSY)
    {
        return HAL_BUSY;
    }

    hSpi->XferState   = HAL_BUSY;
    hSpi->pTxBuffPtr  = (uint8_t *)pData;
    hSpi->TxXferSize  = Size;
    hSpi->TxXferCount = Size;
    hSpi->pRxBuffPtr  = NULL;
    hSpi->RxXferSize  = 0;
    hSpi->RxXferCount = 0;
    hSpi->RxISR       = NULL;

    if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
    {
        hSpi->TxISR = SPI_TxISR_16BIT;
    }
    else
    {
        hSpi->TxISR = SPI_TxISR_8BIT;
    }

    // 单线半双工模式切换总线为输出状态
    if (hSpi->Init.CommLines == SPI_COMM1LINE_HalfDuplex)
    {
        HAL_SPI_1LINE_HALFDUPLEX_TXMODE(hSpi);
    }

    hSpi->Instance->ICR = 0;
    HAL_SPI_ENABLE_IT(hSpi, SPI_IT_SOURCE_TXE);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  通过中断方式接收SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pData      : 待接收的数据的指针
  * @param  Size       : 待接收的数据的帧数
  * @retval HAL status : HAL_OK    表示配置SPI中断方式接收成功
  *                      HAL_ERROR 表示配置SPI中断方式接收失败
  *                      HAL_BUSY  表示SPI正处于通信状态
  * @note   1. 需要在SPIx的中断服务程序中调用 HAL_SPI_IRQHandler 函数
  *         2. 在调用前，需使能NVIC
  *         3. 可用于双线全双工模式接收、单线半双工模式接收、单工模式只收
  *         4. 主机模式调用此函数可以自动发送Dummy以实现clk的输出
  */
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hSpi, uint8_t *pData, uint32_t Size)
{
    if ((hSpi == NULL) || (pData == NULL) || (Size == 0U))
    {
        return HAL_ERROR;
    }
    if (hSpi->XferState == HAL_BUSY)
    {
        return HAL_BUSY;
    }

    // 单线半双工模式切换总线为输入状态
    if (hSpi->Init.CommLines == SPI_COMM1LINE_HalfDuplex)
    {
        HAL_SPI_1LINE_HALFDUPLEX_RXMODE(hSpi);
    }

    // 主机接收模式调用HAL_SPI_TransmitReceive_IT以实现发送Dummy从而产生CLK输出;
    // 包括主机全双工模式接收、主机半双工模式接收、主机单工模式只收
    if (hSpi->Init.WorkMode == SPI_WORKMODE_MASTER)
    {
        return HAL_SPI_TransmitReceive_IT(hSpi, pData, pData, Size);
    }
    // 从机模式只需要接收，不需要发送Dummy
    else
    {
        hSpi->XferState   = HAL_BUSY;
        hSpi->pTxBuffPtr  = NULL;
        hSpi->TxXferSize  = 0;
        hSpi->TxXferCount = 0;
        hSpi->pRxBuffPtr  = (uint8_t *)pData;
        hSpi->RxXferSize  = Size;
        hSpi->RxXferCount = Size;
        hSpi->TxISR       = NULL;

        if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
        {
            hSpi->RxISR = SPI_RxISR_16BIT;
        }
        else
        {
            hSpi->RxISR = SPI_RxISR_8BIT;
        }

        hSpi->Instance->ICR = 0;
        HAL_SPI_ENABLE_IT(hSpi, SPI_IT_SOURCE_RXNE);

        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  通过中断方式发送并接收SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @param  pTxData    : 待发送的数据的指针
  * @param  pRxData    : 待接收的数据的指针
  * @param  Size       : 待发送、接收的数据的帧数
  * @retval HAL status : HAL_OK    表示配置SPI中断方式发送、接收成功
  *                      HAL_ERROR 表示配置SPI中断方式发送、接收失败
  *                      HAL_BUSY  表示SPI正处于通信状态
  * @note   1. 需要在SPIx的中断服务程序中调用 HAL_SPI_IRQHandler 函数
  *         2. 在调用前，需使能NVIC
  *         3. 仅用于双线全双工模式发送、双线全双工模式接收
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hSpi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size)
{
    if ((hSpi == NULL) || (pTxData == NULL) || (pRxData == NULL) || (Size == 0U))
    {
        return HAL_ERROR;
    }
    if (hSpi->XferState == HAL_BUSY)
    {
        return HAL_BUSY;
    }

    hSpi->XferState   = HAL_BUSY;
    hSpi->pTxBuffPtr  = (uint8_t *)pTxData;
    hSpi->TxXferSize  = Size;
    hSpi->TxXferCount = Size;
    hSpi->pRxBuffPtr  = (uint8_t *)pRxData;
    hSpi->RxXferSize  = Size;
    hSpi->RxXferCount = Size;

    if (hSpi->Init.DataWidth > SPI_DATAWIDTH_8BIT)
    {
        hSpi->RxISR = SPI_RxISR_16BIT;
        hSpi->TxISR = SPI_TxISR_16BIT;
    }
    else
    {
        hSpi->RxISR = SPI_RxISR_8BIT;
        hSpi->TxISR = SPI_TxISR_8BIT;
    }

    hSpi->Instance->ICR = 0;
    HAL_SPI_ENABLE_IT(hSpi, SPI_IT_SOURCE_TXE | SPI_IT_SOURCE_RXNE);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  查询待通过中断传输的数据是否完成
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示成功完成发送及接收
  *                      HAL_BUSY  表示正在发送或接收
  *                      HAL_ERROR 表示发送或接收出错
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT_IsComplete(SPI_HandleTypeDef *hSpi)
{
    if (hSpi == NULL)
    {
        return HAL_ERROR;
    }

    if (hSpi->XferState == HAL_BUSY)
    {
        return HAL_BUSY;
    }
    else if (hSpi->XferState == HAL_OK)
    {
        return HAL_OK;
    }
    else
    {
        return HAL_ERROR;
    }
}


/*******************************************************************************
  * @brief  在中断服务程序中发送并接收SPI数据
  * @param  hSpi       : SPI句柄指针，指向包含SPI配置、通信参数的结构体
  * @retval None
  * @note   需要在SPIx的中断服务程序中调用 HAL_SPI_IRQHandler 函数
  *         在调用前，需使能NVIC
  */
void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hSpi)
{
    uint32_t IsrFlags  = hSpi->Instance->ISR;                         // 获取中断标志
    IsrFlags = IsrFlags & hSpi->Instance->IER;                        // 获取有效中断源
    
    if (IsrFlags & SPI_IT_FLAG_RXNE)                                  // 接收缓冲区非空中断
    {
        hSpi->RxISR(hSpi);
    }
    if (IsrFlags & SPI_IT_FLAG_TXE)                                   // 发送缓冲区空中断
    {
        hSpi->TxISR(hSpi);
    }
}


/************************ (C) COPYRIGHT SIYIMicro *****END OF FILE*************/
